/*
 * Copyright (c) 2005, 2006, Oracle and/or its affiliates. All rights reserved.
 * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 */
package de.slothsoft.themes.black;

import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.Paint;
import java.awt.Shape;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Path2D;
import java.awt.geom.Rectangle2D;
import java.awt.geom.RoundRectangle2D;

import javax.swing.JComponent;

final class TextFieldPainter extends AbstractRegionPainter {
	// package private integers representing the available states that
	// this painter will paint. These are used when creating a new instance
	// of TextFieldPainter to determine which region/state is being painted
	// by that instance.
	static final int BACKGROUND_DISABLED = 1;
	static final int BACKGROUND_ENABLED = 2;
	static final int BACKGROUND_SELECTED = 3;
	static final int BORDER_DISABLED = 4;
	static final int BORDER_FOCUSED = 5;
	static final int BORDER_ENABLED = 6;

	private final int state; // refers to one of the static final ints above
	private final PaintContext ctx;

	// the following 4 variables are reused during the painting code of the layers
	private Path2D path = new Path2D.Float();
	private Rectangle2D rect = new Rectangle2D.Float(0, 0, 0, 0);
	private final RoundRectangle2D roundRect = new RoundRectangle2D.Float(0, 0, 0, 0, 0, 0);
	private final Ellipse2D ellipse = new Ellipse2D.Float(0, 0, 0, 0);

	// All Colors used for painting are stored here. Ideally, only those colors being used
	// by a particular instance of TextFieldPainter would be created. For the moment at
	// least,
	// however, all are created for each instance.
	private final Color color1 = decodeColor("blackBlueGrey", -0.015872955f, -0.07995863f, 0.15294117f, 0);
	private final Color color2 = decodeColor("blackLightBackground", 0.0f, 0.0f, 0.0f, 0);
	private final Color color3 = decodeColor("blackBlueGrey", -0.006944418f, -0.07187897f, 0.06666666f, 0);
	private final Color color4 = decodeColor("blackBlueGrey", 0.007936537f, -0.07826825f, 0.10588235f, 0);
	private final Color color5 = decodeColor("blackBlueGrey", 0.007936537f, -0.07856284f, 0.11372548f, 0);
	private final Color color6 = decodeColor("blackBlueGrey", 0.007936537f, -0.07796818f, 0.09803921f, 0);
	private final Color color7 = decodeColor("blackBlueGrey", -0.027777791f, -0.0965403f, -0.18431371f, 0);
	private final Color color8 = decodeColor("blackBlueGrey", 0.055555582f, -0.1048766f, -0.05098039f, 0);
	private final Color color9 = decodeColor("blackLightBackground", 0.6666667f, 0.004901961f, -0.19999999f, 0);
	private final Color color10 = decodeColor("blackBlueGrey", 0.055555582f, -0.10512091f, -0.019607842f, 0);
	private final Color color11 = decodeColor("blackBlueGrey", 0.055555582f, -0.105344966f, 0.011764705f, 0);
	private final Color color12 = decodeColor("blackFocus", 0.0f, 0.0f, 0.0f, 0);

	// Array of current component colors, updated in each paint call
	private Object[] componentColors;

	public TextFieldPainter(PaintContext ctx, int state) {
		super();
		this.state = state;
		this.ctx = ctx;
	}

	@Override
	protected void doPaint(Graphics2D g, JComponent c, int width, int height, Object[] extendedCacheKeys) {
		// populate componentColors array with colors calculated in getExtendedCacheKeys
		// call
		this.componentColors = extendedCacheKeys;
		// generate this entire method. Each state/bg/fg/border combo that has
		// been painted gets its own KEY and paint method.
		switch (this.state) {
		case BACKGROUND_DISABLED:
			paintBackgroundDisabled(g);
			break;
		case BACKGROUND_ENABLED:
			paintBackgroundEnabled(g);
			break;
		case BACKGROUND_SELECTED:
			paintBackgroundSelected(g);
			break;
		case BORDER_DISABLED:
			paintBorderDisabled(g);
			break;
		case BORDER_FOCUSED:
			paintBorderFocused(g);
			break;
		case BORDER_ENABLED:
			paintBorderEnabled(g);
			break;

		}
	}

	@Override
	protected Object[] getExtendedCacheKeys(JComponent c) {
		Object[] extendedCacheKeys = null;
		switch (this.state) {
		case BACKGROUND_ENABLED:
			extendedCacheKeys = new Object[] { getComponentColor(c, "background", this.color2, 0.0f, 0.0f, 0) };
			break;
		case BORDER_FOCUSED:
			extendedCacheKeys = new Object[] {
					getComponentColor(c, "background", this.color9, 0.004901961f, -0.19999999f, 0),
					getComponentColor(c, "background", this.color2, 0.0f, 0.0f, 0) };
			break;
		case BORDER_ENABLED:
			extendedCacheKeys = new Object[] {
					getComponentColor(c, "background", this.color9, 0.004901961f, -0.19999999f, 0),
					getComponentColor(c, "background", this.color2, 0.0f, 0.0f, 0) };
			break;
		}
		return extendedCacheKeys;
	}

	@Override
	protected final PaintContext getPaintContext() {
		return this.ctx;
	}

	private void paintBackgroundDisabled(Graphics2D g) {
		this.rect = decodeRect1();
		g.setPaint(this.color1);
		g.fill(this.rect);

	}

	private void paintBackgroundEnabled(Graphics2D g) {
		this.rect = decodeRect1();
		g.setPaint((Color) this.componentColors[0]);
		g.fill(this.rect);

	}

	private void paintBackgroundSelected(Graphics2D g) {
		this.rect = decodeRect1();
		g.setPaint(this.color2);
		g.fill(this.rect);

	}

	private void paintBorderDisabled(Graphics2D g) {
		this.rect = decodeRect2();
		g.setPaint(decodeGradient1(this.rect));
		g.fill(this.rect);
		this.rect = decodeRect3();
		g.setPaint(decodeGradient2(this.rect));
		g.fill(this.rect);
		this.rect = decodeRect4();
		g.setPaint(this.color6);
		g.fill(this.rect);
		this.rect = decodeRect5();
		g.setPaint(this.color4);
		g.fill(this.rect);
		this.rect = decodeRect6();
		g.setPaint(this.color4);
		g.fill(this.rect);

	}

	private void paintBorderFocused(Graphics2D g) {
		this.rect = decodeRect7();
		g.setPaint(decodeGradient3(this.rect));
		g.fill(this.rect);
		this.rect = decodeRect8();
		g.setPaint(decodeGradient4(this.rect));
		g.fill(this.rect);
		this.rect = decodeRect9();
		g.setPaint(this.color10);
		g.fill(this.rect);
		this.rect = decodeRect10();
		g.setPaint(this.color10);
		g.fill(this.rect);
		this.rect = decodeRect11();
		g.setPaint(this.color11);
		g.fill(this.rect);
		this.path = decodePath1();
		g.setPaint(this.color12);
		g.fill(this.path);

	}

	private void paintBorderEnabled(Graphics2D g) {
		this.rect = decodeRect7();
		g.setPaint(decodeGradient5(this.rect));
		g.fill(this.rect);
		this.rect = decodeRect8();
		g.setPaint(decodeGradient4(this.rect));
		g.fill(this.rect);
		this.rect = decodeRect9();
		g.setPaint(this.color10);
		g.fill(this.rect);
		this.rect = decodeRect10();
		g.setPaint(this.color10);
		g.fill(this.rect);
		this.rect = decodeRect11();
		g.setPaint(this.color11);
		g.fill(this.rect);

	}

	private Rectangle2D decodeRect1() {
		this.rect.setRect(decodeX(0.4f), // x
				decodeY(0.4f), // y
				decodeX(2.6f) - decodeX(0.4f), // width
				decodeY(2.6f) - decodeY(0.4f)); // height
		return this.rect;
	}

	private Rectangle2D decodeRect2() {
		this.rect.setRect(decodeX(0.6666667f), // x
				decodeY(0.4f), // y
				decodeX(2.3333333f) - decodeX(0.6666667f), // width
				decodeY(1.0f) - decodeY(0.4f)); // height
		return this.rect;
	}

	private Rectangle2D decodeRect3() {
		this.rect.setRect(decodeX(1.0f), // x
				decodeY(0.6f), // y
				decodeX(2.0f) - decodeX(1.0f), // width
				decodeY(1.0f) - decodeY(0.6f)); // height
		return this.rect;
	}

	private Rectangle2D decodeRect4() {
		this.rect.setRect(decodeX(0.6666667f), // x
				decodeY(1.0f), // y
				decodeX(1.0f) - decodeX(0.6666667f), // width
				decodeY(2.0f) - decodeY(1.0f)); // height
		return this.rect;
	}

	private Rectangle2D decodeRect5() {
		this.rect.setRect(decodeX(0.6666667f), // x
				decodeY(2.3333333f), // y
				decodeX(2.3333333f) - decodeX(0.6666667f), // width
				decodeY(2.0f) - decodeY(2.3333333f)); // height
		return this.rect;
	}

	private Rectangle2D decodeRect6() {
		this.rect.setRect(decodeX(2.0f), // x
				decodeY(1.0f), // y
				decodeX(2.3333333f) - decodeX(2.0f), // width
				decodeY(2.0f) - decodeY(1.0f)); // height
		return this.rect;
	}

	private Rectangle2D decodeRect7() {
		this.rect.setRect(decodeX(0.4f), // x
				decodeY(0.4f), // y
				decodeX(2.6f) - decodeX(0.4f), // width
				decodeY(1.0f) - decodeY(0.4f)); // height
		return this.rect;
	}

	private Rectangle2D decodeRect8() {
		this.rect.setRect(decodeX(0.6f), // x
				decodeY(0.6f), // y
				decodeX(2.4f) - decodeX(0.6f), // width
				decodeY(1.0f) - decodeY(0.6f)); // height
		return this.rect;
	}

	private Rectangle2D decodeRect9() {
		this.rect.setRect(decodeX(0.4f), // x
				decodeY(1.0f), // y
				decodeX(0.6f) - decodeX(0.4f), // width
				decodeY(2.6f) - decodeY(1.0f)); // height
		return this.rect;
	}

	private Rectangle2D decodeRect10() {
		this.rect.setRect(decodeX(2.4f), // x
				decodeY(1.0f), // y
				decodeX(2.6f) - decodeX(2.4f), // width
				decodeY(2.6f) - decodeY(1.0f)); // height
		return this.rect;
	}

	private Rectangle2D decodeRect11() {
		this.rect.setRect(decodeX(0.6f), // x
				decodeY(2.4f), // y
				decodeX(2.4f) - decodeX(0.6f), // width
				decodeY(2.6f) - decodeY(2.4f)); // height
		return this.rect;
	}

	private Path2D decodePath1() {
		this.path.reset();
		this.path.moveTo(decodeX(0.4f), decodeY(0.4f));
		this.path.lineTo(decodeX(0.4f), decodeY(2.6f));
		this.path.lineTo(decodeX(2.6f), decodeY(2.6f));
		this.path.lineTo(decodeX(2.6f), decodeY(0.4f));
		this.path.curveTo(decodeAnchorX(2.5999999046325684f, 0.0f), decodeAnchorY(0.4000000059604645f, 0.0f),
				decodeAnchorX(2.880000352859497f, 0.09999999999999432f), decodeAnchorY(0.4000000059604645f, 0.0f),
				decodeX(2.8800004f), decodeY(0.4f));
		this.path.curveTo(decodeAnchorX(2.880000352859497f, 0.09999999999999432f),
				decodeAnchorY(0.4000000059604645f, 0.0f), decodeAnchorX(2.880000352859497f, 0.0f),
				decodeAnchorY(2.879999876022339f, 0.0f), decodeX(2.8800004f), decodeY(2.8799999f));
		this.path.lineTo(decodeX(0.120000005f), decodeY(2.8799999f));
		this.path.lineTo(decodeX(0.120000005f), decodeY(0.120000005f));
		this.path.lineTo(decodeX(2.8800004f), decodeY(0.120000005f));
		this.path.lineTo(decodeX(2.8800004f), decodeY(0.4f));
		this.path.lineTo(decodeX(0.4f), decodeY(0.4f));
		this.path.closePath();
		return this.path;
	}

	private Paint decodeGradient1(Shape s) {
		Rectangle2D bounds = s.getBounds2D();
		float x = (float) bounds.getX();
		float y = (float) bounds.getY();
		float w = (float) bounds.getWidth();
		float h = (float) bounds.getHeight();
		return decodeGradient((0.5f * w) + x, (0.0f * h) + y, (0.5f * w) + x, (1.0f * h) + y, new float[] { 0.0f, 0.5f,
				1.0f }, new Color[] { this.color3, decodeColor(this.color3, this.color4, 0.5f), this.color4 });
	}

	private Paint decodeGradient2(Shape s) {
		Rectangle2D bounds = s.getBounds2D();
		float x = (float) bounds.getX();
		float y = (float) bounds.getY();
		float w = (float) bounds.getWidth();
		float h = (float) bounds.getHeight();
		return decodeGradient((0.5f * w) + x, (0.0f * h) + y, (0.5f * w) + x, (1.0f * h) + y, new float[] { 0.0f, 0.5f,
				1.0f }, new Color[] { this.color5, decodeColor(this.color5, this.color1, 0.5f), this.color1 });
	}

	private Paint decodeGradient3(Shape s) {
		Rectangle2D bounds = s.getBounds2D();
		float x = (float) bounds.getX();
		float y = (float) bounds.getY();
		float w = (float) bounds.getWidth();
		float h = (float) bounds.getHeight();
		return decodeGradient((0.25f * w) + x, (0.0f * h) + y, (0.25f * w) + x, (0.1625f * h) + y, new float[] { 0.1f,
				0.49999997f, 0.9f }, new Color[] { this.color7, decodeColor(this.color7, this.color8, 0.5f),
				this.color8 });
	}

	private Paint decodeGradient4(Shape s) {
		Rectangle2D bounds = s.getBounds2D();
		float x = (float) bounds.getX();
		float y = (float) bounds.getY();
		float w = (float) bounds.getWidth();
		float h = (float) bounds.getHeight();
		return decodeGradient(
				(0.5f * w) + x,
				(0.0f * h) + y,
				(0.5f * w) + x,
				(1.0f * h) + y,
				new float[] { 0.1f, 0.49999997f, 0.9f },
				new Color[] { (Color) this.componentColors[0],
						decodeColor((Color) this.componentColors[0], (Color) this.componentColors[1], 0.5f),
						(Color) this.componentColors[1] });
	}

	private Paint decodeGradient5(Shape s) {
		Rectangle2D bounds = s.getBounds2D();
		float x = (float) bounds.getX();
		float y = (float) bounds.getY();
		float w = (float) bounds.getWidth();
		float h = (float) bounds.getHeight();
		return decodeGradient((0.5f * w) + x, (0.0f * h) + y, (0.5f * w) + x, (1.0f * h) + y, new float[] { 0.1f,
				0.49999997f, 0.9f }, new Color[] { this.color7, decodeColor(this.color7, this.color8, 0.5f),
				this.color8 });
	}

}
